import mapboxgl from 'mapbox-gl';
import type { Mapless } from '..';
import { Manager } from '../core/manager';
import { createIconElement } from '../core/utils';
import type { ManagerOptions } from '../index.d';

class MarkerManager extends Manager {
  private markers: Record<string, mapboxgl.Marker> = {};

  constructor(mapless: Mapless, options?: ManagerOptions) {
    super(mapless, options, 'marker');
    this.onInitialized();
  }

  getMarkers() {
    return this.markers;
  }

  addMarker(
    id: string,
    lnglat: [number, number],
    options: {
      icon?: string;
      color?: string;
      popup?: string;
    },
  ) {
    if (!this.map) return;
    let icon = {};
    if (options.icon && this.mapless?.hasIcon(options.icon)) {
      const url = this.mapless.getIconUrl(options.icon);
      if (url) {
        icon = { element: createIconElement(url) };
      }
    }
    const marker = new mapboxgl.Marker({
      color: options.color,
      ...icon,
    })
      .setLngLat(lnglat)
      .addTo(this.map);
    // 给marker元素添加data-属性
    const element = marker.getElement();
    if (element) {
      element.id = id;
    }
    if (options.popup) {
      marker.setPopup(new mapboxgl.Popup().setHTML(options.popup));
    }
    this.markers[id] = marker;
  }

  /**
   * 通用更新标记点方法
   * @param id 标记点ID
   * @param options 更新选项
   * @param options.lnglat 新坐标 [经度, 纬度]
   * @param options.icon 新图标
   * @param options.popup 新弹出内容
   */
  updateMarker(
    id: string,
    options: {
      lnglat?: [number, number];
      popup?: string;
    },
  ) {
    const marker = this.markers[id];
    if (!marker || !this.map) return;
    // 更新坐标
    if (options.lnglat) {
      marker.setLngLat(options.lnglat);
    }
    // 更新弹出内容
    if (options.popup !== undefined) {
      if (options.popup) {
        marker.setPopup(new mapboxgl.Popup().setHTML(options.popup));
      } else {
        marker.getPopup()?.remove();
      }
    }
  }

  removeMarker(id: string) {
    if (this.markers[id]) {
      this.markers[id].remove();
      delete this.markers[id];
    }
  }

  override destroy = () => {
    Object.values(this.markers).forEach((marker) => {
      marker.remove();
    });
    this.markers = {};
  };
}

export default MarkerManager;

export const attachMarker = (mapless: Mapless | undefined, name?: string) =>
  mapless?.use(MarkerManager, name);
export const getMarker = (mapless: Mapless | undefined, name?: string) =>
  mapless?.get(MarkerManager, name);
export const detachMarker = (mapless: Mapless | undefined, name?: string) =>
  mapless?.unuse(MarkerManager, name);
